#ifndef __M_HOST_H__
#define __M_HOST_H__
#include "mq_exchange.hpp"
#include "mq_queue.hpp"
#include "mq_binding.hpp"
#include "mq_message.hpp"

namespace mymq
{
    class VirtualHost
    {
    public:
        using ptr = std::shared_ptr<VirtualHost>;
        VirtualHost(const std::string& hname, const std::string& basedir, const std::string& dbfile)
        : _host_name(hname),
          _exchange_manager(std::make_shared<ExchangeManager>(dbfile)),
          _msgqueue_manager(std::make_shared<MsgQueueManager>(dbfile)),
          _binding_manager(std::make_shared<BindingManager>(dbfile)),
          _message_manager(std::make_shared<MessgeManager>(basedir))
        {
            // 交换机，队列，绑定 这三个句柄在构造时就会自动恢复历史数据
            // 但是消息句柄只有在 声明队列消息 时才会进行恢复，所以这里手动调用 initQueueMessage

            // 获得所有队列的名字
            QueueMap qm = _msgqueue_manager->getAllQueues();
            for (auto& queue : qm)
                _message_manager->initQueueMessage(queue.first);
        }

        bool declareExchange(const std::string& name, ExchangeType type, bool durable, 
            bool auto_delete, const google::protobuf::Map<std::string, std::string>& args)
        {
            return _exchange_manager->declareExchange(name, type, durable, auto_delete, args);
        }
        void deleteExchange(const std::string& name)
        {
            _exchange_manager->deleteExchange(name);
            // 交换机删除后，绑定信息就没有必要存在了
            _binding_manager->removeExchangeBindings(name);
        }
        Exchange::ptr selectExchange(const std::string& ename)
        {
            return _exchange_manager->selectExchange(ename);
        }

        bool declareQueue(const std::string& qname, bool qdurable, bool qexclusive, bool qauto_delete,
            const google::protobuf::Map<std::string, std::string>& qargs)
        {
            // 初始化队列消息句柄，消息存储管理
            _message_manager->initQueueMessage(qname);

            return _msgqueue_manager->declareQueue(qname, qdurable, qexclusive, qauto_delete, qargs);
        }
        void deleteQueue(const std::string& name)
        {
            _msgqueue_manager->deleteQueue(name);
            // 删除队列后，相关的绑定信息也要删除
            _binding_manager->removeMsgQueueBindings(name);
            // 队列不存在了，那么队列消息也就不存在了
            _message_manager->destroyQueueMessage(name);
        }

        bool bind(const std::string& ename, const std::string& qname, const std::string& key)
        {
            // 查找交换机
            Exchange::ptr ep = _exchange_manager->selectExchange(ename);
            if (ep.get() == nullptr)
            {
                DLOG("绑定失败：交换机 %s 不存在", ename.c_str());
                return false;
            }
            // 查找队列
            MsgQueue::ptr qp = _msgqueue_manager->selectQueue(qname);
            if (qp.get() == nullptr)
            {
                DLOG("绑定失败：队列 %s 不存在", qname.c_str());
                return false;
            }

            // 绑定要不要持久化，取决于 交换机和队列，只有两者都持久化的情况下，绑定才持久化
            return _binding_manager->bind(ename, qname, key, ep->durable && qp->durable);
        }
        void unBind(const std::string& ename, const std::string& qname)
        {
            _binding_manager->unBind(ename, qname);
        }
        MsgQueueBindingMap getExchangeBindings(const std::string& ename)
        {
            return _binding_manager->getExchangeBindings(ename);
        }

        bool basicPublish(const std::string& qname, BasicProperties* bp, const std::string& body)
        {
            // 消息的持久化与否取决于队列是否初始化，所以先获取指定队列
            MsgQueue::ptr qp = _msgqueue_manager->selectQueue(qname);
            if (qp.get() == nullptr)
            {
                DLOG("发布消息失败：队列 %s 不存在！", qname.c_str());
                return false;
            }
            return _message_manager->insert(qname, bp, body, qp->durable);
        }
        MessagePtr basicConsume(const std::string& qname)
        {
            return _message_manager->front(qname);
        }
        void basicAck(const std::string& qname, const std::string& msg_id)
        {
            return _message_manager->ack(qname, msg_id);
        }

        void clear()
        {
            _exchange_manager->clear();
            _msgqueue_manager->clear();
            _binding_manager->clear();
            _message_manager->clear();
        }

        // test
        bool existsExchange(const std::string& name)
        {
            return _exchange_manager->exists(name);
        }
        bool existsQueue(const std::string& name)
        {
            return _msgqueue_manager->exists(name);
        }
        bool existsBinding(const std::string& ename, const std::string& qname)
        {
            return _binding_manager->exists(ename, qname);
        }
    private:
        std::string _host_name;
        ExchangeManager::ptr _exchange_manager;
        MsgQueueManager::ptr _msgqueue_manager;
        BindingManager:: ptr _binding_manager;
        MessgeManager::ptr _message_manager;
    };
}

#endif